/**
 * Facebook Animation Class
 * Copyright (C) 2010 Facebook
 *
 * Original function by Facebook from: http://github.com/facebook/animation
 * 
 * Licensed under the Facebook CLA license agreement: http://developers.facebook.com/licensing
 */
Function.prototype.bind = function (b)
{
	var a = [b, this].concat(Array.prototype.slice.call(arguments, 1));
	return bind.apply(null, a);
};
function copy_properties(b, c)
{
	b = b || {};
	c = c || {};
	for (var a in c) {
		b[a] = c[a];
	}
	if (c.hasOwnProperty && c.hasOwnProperty('toString') && (typeof c.toString != 'undefined') && (b.toString !== c.toString)) {
		b.toString = c.toString;
	}
	return b;
}
function add_properties(a, b)
{
	return copy_properties(window[a] || (window[a] = {}), b);
}

add_properties('CSS', 
{
	$ : function (a) {
		return typeof a == "string" ? document.getElementById(a) : a;
	},
	supportsBorderRadius : function ()
	{
		var c = ['KhtmlBorderRadius', 'OBorderRadius', 'MozBorderRadius', 'WebkitBorderRadius', 'msBorderRadius', 
		'borderRadius'];
		var d = false, a = document.createElement('div');
		for (var b = c.length; b >= 0; b--) {
			if (d = a.style[c[b]] !== undefined) {
				break;
			}
			CSS.supportsBorderRadius = bagof(d);
			return d;;
		}
	},
	hasClass : function (b, a) 
		{
		b = CSS.$(b);
		return (" " + b.className + " ").indexOf(" " + a + " ") > - 1;
	},
	addClass : function (b, a) 
	{
		b = CSS.$(b);
		if (a && !CSS.hasClass(b, a)) {
			b.className = b.className + (" " + a);
		}
		return b;
	},
	removeClass : function (b, a) 
	{
		b = CSS.$(b);
		b.className = b.className.replace(new RegExp("(^|\\s)" + a + "(?:\\s|$)", "g"), "$1");
		return b;
	},
	toggleClass : function (b, a) 
	{
		return CSS.conditionClass(b, a, !CSS.hasClass(b, a));
	},
	conditionClass : function (c, b, a) 
	{
		return (a ? CSS.addClass : CSS.removeClass)(c, b);
	},
	show : function (a) 
	{
		CSS.removeClass(a, "hidden_elem");
	},
	hide : function (a) 
	{
		CSS.addClass(a, "hidden_elem");
	},
	toggle : function (a) 
	{
		CSS.toggleClass(a, "hidden_elem");
	},
	shown : function (a) 
	{
		return !CSS.hasClass(a, "hidden_elem");
	},
	setClass : function (b, a) 
	{
		CSS.$(b).className = a || "";
		return b;
	},
	setStyle : function (a, b, d) 
	{
		switch (b) 
		{
			case "opacity":
				var c = d == 1;
				a.style.opacity = c ? "" : "" + d;
				a.style.filter = c ? "" : "alpha(opacity=" + d * 100 + ")";
				break;
			case "float":
				a.style.cssFloat = a.style.styleFloat = d;
				break;
			default:
				b = b.replace(/-(.)/g, function (e, f) 
				{
					return f.toUpperCase();
				});
				a.style[b] = d;
		}
		return a;
	},
	getStyle : function (b, d) 
	{
		b = CSS.$(b);
		function c(e) 
		{
			return e.replace(/([A-Z])/g, "-$1").toLowerCase();
		}
		if (window.getComputedStyle) {
			var a = window.getComputedStyle(b, null);
			if (a) {
				return a.getPropertyValue(c(d));
			}
		}
		if (document.defaultView && document.defaultView.getComputedStyle) 
		{
			var a = document.defaultView.getComputedStyle(b, null);
			if (a) {
				return a.getPropertyValue(c(d));
			}
			if (d == "display") {
				return "none";
			}
		}
		if (b.currentStyle) {
			return b.currentStyle[d];
		}
		return b.style[d];
	},
	getOpacity : function (a) 
	{
		a = CSS.$(a);
		var b = CSS.getStyle(a, "filter");
		var c = null;
		if (b && (c = /(\d+(?:\.\d+)?)/.exec(b))) {
			return parseFloat(c.pop())	/ 100;
		}
		else if ((b = CSS.getStyle(a, "opacity"))) {
			return parseFloat(b);
		}
		else {
			return 1;
		}
	}
});

function animation(a)
{
	if (a == undefined) {
		return;
	}
	if (this == window) {
		return new animation(a);
	}
	else {
		this.obj = a;
		this._reset_state();
		this.queue = [];
		this.last_attr = null;
	}
}
animation.resolution = 20;
animation.offset = 0;
animation.prototype._reset_state = function ()
{
	this.state = {
		attrs : {}, duration : 500
	};
};
animation.prototype.stop = function ()
{
	this._reset_state();
	this.queue = [];
	return this;
};
animation.prototype._build_container = function ()
{
	if (this.container_div) {
		this._refresh_container();
		return;
	}
	if (this.obj.firstChild && this.obj.firstChild.__animation_refs)
	{
		this.container_div = this.obj.firstChild;
		this.container_div.__animation_refs++;
		this._refresh_container();
		return;
	}
	var b = document.createElement('div');
	b.style.padding = '0px';
	b.style.margin = '0px';
	b.style.border = '0px';
	b.__animation_refs = 1;
	var a = this.obj.childNodes;
	while (a.length) {
		b.appendChild(a[0]);
	}
	this.obj.appendChild(b);
	this.obj.style.overflow = 'hidden';
	this.container_div = b;
	this._refresh_container();
};
animation.prototype._refresh_container = function ()
{
	this.container_div.style.height = 'auto';
	this.container_div.style.width = 'auto';
	this.container_div.style.height = this.container_div.offsetHeight + 'px';
	this.container_div.style.width = this.container_div.offsetWidth + 'px';
};
animation.prototype._destroy_container = function ()
{
	if (!this.container_div) {
		return;
	}
	if (!--this.container_div.__animation_refs)
	{
		var a = this.container_div.childNodes;
		while (a.length) {
			this.obj.appendChild(a[0]);
		}
		this.obj.removeChild(this.container_div);
	}
	this.container_div = null;
};
animation.ATTR_TO = 1;
animation.ATTR_BY = 2;
animation.ATTR_FROM = 3;
animation.prototype._attr = function (a, d, c)
{
	a = a.replace(/-[a-z]/gi, function (e)
	{
		return e.substring(1).toUpperCase();
	});
	var b = false;
	switch (a)
	{
		case 'background':
			this._attr('backgroundColor', d, c);
			return this;
		case 'margin':
			d = animation.parse_group(d);
			this._attr('marginBottom', d[0], c);
			this._attr('marginLeft', d[1], c);
			this._attr('marginRight', d[2], c);
			this._attr('marginTop', d[3], c);
			return this;
		case 'padding':
			d = animation.parse_group(d);
			this._attr('paddingBottom', d[0], c);
			this._attr('paddingLeft', d[1], c);
			this._attr('paddingRight', d[2], c);
			this._attr('paddingTop', d[3], c);
			return this;
		case 'backgroundColor':
		case 'borderColor':
		case 'color':
			d = animation.parse_color(d);
			break;
		case 'opacity':
			d = parseFloat(d, 10);
			break;
		case 'height':
		case 'width':
			if (d == 'auto') {
				b = true;
			}
			else {
				d = parseInt(d, 10);
			}
			break;
		case 'borderWidth':
		case 'lineHeight':
		case 'fontSize':
		case 'marginBottom':
		case 'marginLeft':
		case 'marginRight':
		case 'marginTop':
		case 'paddingBottom':
		case 'paddingLeft':
		case 'paddingRight':
		case 'paddingTop':
		case 'bottom':
		case 'left':
		case 'right':
		case 'top':
		case 'scrollTop':
		case 'scrollLeft':
			d = parseInt(d, 10);
			break;
		default:
			throw new Error(a + ' is not a supported attribute!');
	}
	if (this.state.attrs[a] === undefined) {
		this.state.attrs[a] = {};
	}
	if (b) {
		this.state.attrs[a].auto = true;
	}
	switch (c)
	{
		case animation.ATTR_FROM:
			this.state.attrs[a].start = d;
			break;
		case animation.ATTR_BY:
			this.state.attrs[a].by = true;
		case animation.ATTR_TO:
			this.state.attrs[a].value = d;
			break;
	}
};
animation._get_box_width = function (c)
{
	var d = parseInt(CSS.getStyle(c, 'paddingLeft'), 10), e = parseInt(CSS.getStyle(c, 'paddingRight'), 
	10), a = parseInt(CSS.getStyle(c, 'borderLeftWidth'), 10), b = parseInt(CSS.getStyle(c, 'borderRightWidth'), 
	10);
	return c.offsetWidth - (d ? d : 0) - (e ? e : 0) - (a ? a : 0) - (b ? b : 0);
};
animation._get_box_height = function (c)
{
	var e = parseInt(CSS.getStyle(c, 'paddingTop'), 10), d = parseInt(CSS.getStyle(c, 'paddingBottom'), 
	10), a = parseInt(CSS.getStyle(c, 'borderTopWidth'), 10), b = parseInt(CSS.getStyle(c, 'borderBottomWidth'), 
	10);
	return c.offsetHeight - (e ? e : 0) - (d ? d : 0) - (a ? a : 0) - (b ? b : 0);
};
animation.prototype.to = function (a, b)
{
	if (b === undefined) {
		this._attr(this.last_attr, a, animation.ATTR_TO);
	}
	else {
		this._attr(a, b, animation.ATTR_TO);
		this.last_attr = a;
	}
	return this;
};
animation.prototype.by = function (a, b)
{
	if (b === undefined) {
		this._attr(this.last_attr, a, animation.ATTR_BY);
	}
	else {
		this._attr(a, b, animation.ATTR_BY);
		this.last_attr = a;
	}
	return this;
};
animation.prototype.from = function (a, b)
{
	if (b === undefined) {
		this._attr(this.last_attr, a, animation.ATTR_FROM);
	}
	else {
		this._attr(a, b, animation.ATTR_FROM);
		this.last_attr = a;
	}
	return this;
};
animation.prototype.duration = function (a)
{
	this.state.duration = a ? a : 0;
	return this;
};
animation.prototype.checkpoint = function (b, a)
{
	if (b === undefined) {
		b = 1;
	}
	this.state.checkpoint = b;
	this.queue.push(this.state);
	this._reset_state();
	this.state.checkpointcb = a;
	return this;
};
animation.prototype.blind = function ()
{
	this.state.blind = true;
	return this;
};
animation.prototype.hide = function ()
{
	this.state.hide = true;
	return this;
};
animation.prototype.show = function ()
{
	this.state.show = true;
	return this;
};
animation.prototype.ease = function (a)
{
	this.state.ease = a;
	return this;
};
animation.prototype.go = function ()
{
	var b = (new Date()).getTime();
	this.queue.push(this.state);
	for (var a = 0; a < this.queue.length; a++)
	{
		this.queue[a].start = b - animation.offset;
		if (this.queue[a].checkpoint) {
			b += this.queue[a].checkpoint * this.queue[a].duration;
		}
	}
	animation.push(this);
	return this;
};
animation.prototype._show = function ()
{
	CSS.show(this.obj);
};
animation.prototype._hide = function ()
{
	CSS.hide(this.obj);
};
animation.prototype._frame = function (l)
{
	var d = true;
	var k = false;
	var n = false;
	for (var e = 0; e < this.queue.length; e++)
	{
		var b = this.queue[e];
		if (b.start > l) {
			d = false;
			continue;
		}
		if (b.checkpointcb) {
			this._callback(b.checkpointcb, l - b.start);
			b.checkpointcb = null;
		}
		if (b.started === undefined)
		{
			if (b.show) {
				this._show();
			}
			for (var a in b.attrs)
			{
				if (b.attrs[a].start !== undefined) {
					continue;
				}
				switch (a)
				{
					case 'backgroundColor':
					case 'borderColor':
					case 'color':
						var m = animation.parse_color(CSS.getStyle(this.obj, a == 'borderColor' ? 'borderLeftColor' : a));
						if (b.attrs[a].by)
						{
							b.attrs[a].value[0] = Math.min(255, Math.max(0, b.attrs[a].value[0] + m[0]));
							b.attrs[a].value[1] = Math.min(255, Math.max(0, b.attrs[a].value[1] + m[1]));
							b.attrs[a].value[2] = Math.min(255, Math.max(0, b.attrs[a].value[2] + m[2]));
						}
						break;
					case 'opacity':
						var m = CSS.getOpacity(this.obj);
						if (b.attrs[a].by) {
							b.attrs[a].value = Math.min(1, Math.max(0, b.attrs[a].value + m));
						}
						break;
					case 'height':
						var m = animation._get_box_height(this.obj);
						if (b.attrs[a].by) {
							b.attrs[a].value += m;
						}
						break;
					case 'width':
						var m = animation._get_box_width(this.obj);
						if (b.attrs[a].by) {
							b.attrs[a].value += m;
						}
						break;
					case 'scrollLeft':
					case 'scrollTop':
						var m = (this.obj == document.body) ? (document.documentElement[a] || document.body[a]) : this.obj[a];
						if (b.attrs[a].by) {
							b.attrs[a].value += m;
						}
						b['last' + a] = m;
						break;
					default:
						var m = parseInt(CSS.getStyle(this.obj, a), 10) || 0;
						if (b.attrs[a].by) {
							b.attrs[a].value += m;
						}
						break;
				}
				b.attrs[a].start = m;
			}
			if ((b.attrs.height && b.attrs.height.auto) || (b.attrs.width && b.attrs.width.auto))
			{
				if (ua.firefox() < 3) {
					n = true;
				}
				this._destroy_container();
				for (var a in 
				{
					height : 1, width : 1, fontSize : 1, borderLeftWidth : 1, borderRightWidth : 1, borderTopWidth : 1, 
					borderBottomWidth : 1, paddingLeft : 1, paddingRight : 1, paddingTop : 1, paddingBottom : 1
				}) if (b.attrs[a]) this.obj.style[a] = b.attrs[a].value + (typeof b.attrs[a].value == 'number' ? 'px' : '');
				if (b.attrs.height && b.attrs.height.auto) {
					b.attrs.height.value = animation._get_box_height(this.obj);
				}
				if (b.attrs.width && b.attrs.width.auto) {
					b.attrs.width.value = animation._get_box_width(this.obj);
				}
			}
			b.started = true;
			if (b.blind) {
				this._build_container();
			}
		}
		var h = (l - b.start) / b.duration;
		if (h >= 1) {
			h = 1;
			if (b.hide) {
				this._hide();
			}
		}
		else {
			d = false;
		}
		var j = b.ease ? b.ease(h) : h;
		if (!k && h != 1 && b.blind) {
			k = true;
		}
		if (n && this.obj.parentNode) {
			var i = this.obj.parentNode;
			var g = this.obj.nextSibling;
			i.removeChild(this.obj);
		}
		for (var a in b.attrs)
		{
			switch (a) 
			{
				case 'backgroundColor':
				case 'borderColor':
				case 'color':
					this.obj.style[a] = 'rgb(' + animation.calc_tween(j, b.attrs[a].start[0], b.attrs[a].value[0], 
					true) + ',' + animation.calc_tween(j, b.attrs[a].start[1], b.attrs[a].value[1], true) + ',' + animation.calc_tween(j, 
					b.attrs[a].start[2], b.attrs[a].value[2], true) + ')';
					break;
				case 'opacity':
					CSS.setStyle(this.obj, 'opacity', animation.calc_tween(j, b.attrs[a].start, b.attrs[a].value));
					break;
				case 'height':
				case 'width':
					this.obj.style[a] = j == 1 && b.attrs[a].auto ? 'auto' : animation.calc_tween(j, b.attrs[a].start, 
					b.attrs[a].value, true) + 'px';
					break;
				case 'scrollLeft':
				case 'scrollTop':
					var f = this.obj == document.body;
					var m = (f) ? (document.documentElement[a] || document.body[a]) : this.obj[a];
					if (b['last' + a] != m) {
						delete b.attrs[a];
					}
					else 
					{
						var c = animation.calc_tween(j, b.attrs[a].start, b.attrs[a].value, true) - m;
						if (!f) {
							this.obj[a] = c + m;
						}
						else if (a == 'scrollLeft') {
							window.scrollBy(c, 0);
						}
						else {
							window.scrollBy(0, c);
						}
						b['last' + a] = c + m;
					}
					break;
				default:
					this.obj.style[a] = animation.calc_tween(j, b.attrs[a].start, b.attrs[a].value, true) + 'px';
					break;
			}
		}
		if (h == 1) {
			this.queue.splice(e--, 1);
			this._callback(b.ondone, l - b.start - b.duration);
		}
	}
	if (n) {
		i[g ? 'insertBefore' : 'appendChild'](this.obj, g);
	}
	if (!k && this.container_div) {
		this._destroy_container();
	}
	return !d;
};
animation.prototype.ondone = function (a)
{
	this.state.ondone = a;
	return this;
};
animation.prototype._callback = function (a, b)
{
	if (a) {
		animation.offset = b;
		a.call(this);
		animation.offset = 0;
	}
};
animation.calc_tween = function (a, b, c, d)
{
	return (d ? parseInt : parseFloat)((c - b) * a + b, 10);
};
animation.parse_color = function (a)
{
	var b = /^#([a-f0-9]{1,2})([a-f0-9]{1,2})([a-f0-9]{1,2})$/i.exec(a);
	if (b)
	{
		return [parseInt(b[1].length == 1 ? b[1] + b[1] : b[1], 16), parseInt(b[2].length == 1 ? b[2] + b[2] : b[2], 
		16), parseInt(b[3].length == 1 ? b[3] + b[3] : b[3], 16)];
	}
	else
	{
		var c = /^rgba? *\(([0-9]+), *([0-9]+), *([0-9]+)(?:, *([0-9]+))?\)$/.exec(a);
		if (c)
		{
			if (c[4] === '0') {
				return [255, 255, 255];
			}
			else {
				return [parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10)];
			}
		}
		else if (a == 'transparent') {
			return [255, 255, 255];
		}
		else {
			throw 'Named color attributes are not supported.';
		}
	}
};
animation.parse_group = function (a)
{
	var a = trim(a).split(/ +/);
	if (a.length == 4) {
		return a;
	}
	else if (a.length == 3) {
		return [a[0], a[1], a[2], a[1]];
	}
	else if (a.length == 2) {
		return [a[0], a[1], a[0], a[1]];
	}
	else {
		return [a[0], a[0], a[0], a[0]];
	}
};
animation.push = function (a)
{
	if (!animation.active) {
		animation.active = [];
	}
	animation.active.push(a);
	if (!animation.timeout)
	{
		animation.timeout = setInterval(animation.animate.bind(animation), animation.resolution, false);
	}
	animation.animate(true);
};
animation.animate = function (c)
{
	var d = (new Date()).getTime();
	for (var b = c === true ? animation.active.length - 1 : 0; b < animation.active.length; b++)
	{
		try {
			if (!animation.active[b]._frame(d)) {
				animation.active.splice(b--, 1);
			}
		}
		catch (a) {
			animation.active.splice(b--, 1);
		}
	}
	if (animation.active.length == 0) {
		clearInterval(animation.timeout);
		animation.timeout = null;
	}
};
var bind = function(d, c)
{
	var a = Array.prototype.slice.call(arguments, 2);
	var b = function ()
	{
		var f = d || (this == window ? false : this), e = a.concat(Array.prototype.slice.call(arguments));
		if (typeof (c) == "string") {
			if (f[c]) {
				return f[c].apply(f, e);
			}
		}
		else {
			return c.apply(f, e);
		}
	};
	if (typeof c == 'string') {
		b.name = c;
	}
	else if (c && c.name) {
		b.name = c.name;
	}
	b.toString = function ()
	{
		return bind._toString(d, a, c);
	};
	return b;
};
animation.ease = {};
animation.ease.begin = function (a)
{
	return Math.sin(Math.PI / 2 * (a - 1)) + 1;
};
animation.ease.end = function (a)
{
	return Math.sin(.5 * Math.PI * a);
};
animation.ease.both = function (a)
{
	return .5 * Math.sin(Math.PI * (a - .5)) + .5;
};
animation.prependInsert = function (b, a)
{
	animation.insert(b, a, DOM.prependContent);
};
animation.appendInsert = function (b, a)
{
	animation.insert(b, a, DOM.appendContent);
};
animation.insert = function (c, a, b)
{
	CSS.setStyle(a, 'opacity', 0);
	b(c, a);
	animation(a).from('opacity', 0).to('opacity', 1).duration(400).go();
};

Animation = animation;